package ias.deepsearch.com.helper.util.normal;

import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.TextView;

import com.google.gson.Gson;
import com.socks.library.KLog;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import ias.deepsearch.com.helper.model.dp.ViewNode;
import ias.deepsearch.com.helper.model.util.UtilViewNode;
import ias.deepsearch.com.helper.util.BuildConfig;
import ias.deepsearch.com.helper.util.webview.RobotiumWebClient;

/**
 * Created by vector on 16/7/24.
 */
public class ViewUtil {


    Activity currentActivity;
    View root;

    String webContent = "";

    public String getWebContent() {
        return webContent;
    }

    public void setWebContent(String webContent) {
        this.webContent = webContent;

        KLog.v(Constants.WEB_TAG, "==========get Content and set the webContent============");
        //KLog.v(Constants.WEB_TAG, webContent);
    }

    public ViewUtil(Activity currentActivity) {
        this.currentActivity = currentActivity;
        root = currentActivity.getWindow().getDecorView();
    }


    public static String getLast(String name){
        String[] words = name.split("\\.");
        //Log.v("liuyi", words[words.length-1]);
        return  words[words.length-1];
    }

    private boolean isDerivedFrom(Class c, Class p) {
        while(c != Object.class) {
            if(c == p)
                return true;
            c = c.getSuperclass();
        }
        return false;
    }

    public void getWebContent(final WebView root)
    {


        KLog.v(Constants.WEB_TAG, "getContent from webview");

        //enable js
        root.getSettings().setJavaScriptEnabled(true);

//        //enable our jsbridge
//        root.addJavascriptInterface(new IASJSBridge(), "iasInterface");

        //enable our WebChromeClient to deal with prompt function
        WebChromeClient currentWebChromeClient = getCurrentWebChromeClient(root);
        RobotiumWebClient robotiumWebCLient = new RobotiumWebClient(currentActivity, this);
        WebChromeClient originalWebChromeClient = null ;

        if(currentWebChromeClient != null && !currentWebChromeClient.getClass().isAssignableFrom(RobotiumWebClient.class)){
            originalWebChromeClient = currentWebChromeClient;
        }

        robotiumWebCLient.enableJavascriptAndSetRobotiumWebClient(root, originalWebChromeClient);


        KLog.v(Constants.WEB_TAG, "==========try to get the content of target webview==========");
        currentActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                root.loadUrl("javascript:prompt('ias' + document.getElementsByTagName(\"html\")[0].outerHTML);");
            }
        });

    }

    private WebChromeClient getCurrentWebChromeClient(WebView webview){
        WebChromeClient currentWebChromeClient = null;

        Object currentWebView = webview;

        if (android.os.Build.VERSION.SDK_INT >= 16) {
            try{
                currentWebView = new Reflect(currentWebView).field("mProvider").out(Object.class);
            }catch(IllegalArgumentException ignored) {}
        }

        try{
            if (android.os.Build.VERSION.SDK_INT >= 19) {
                Object mClientAdapter = new Reflect(currentWebView).field("mContentsClientAdapter").out(Object.class);
                currentWebChromeClient = new Reflect(mClientAdapter).field("mWebChromeClient").out(WebChromeClient.class);
            }
            else {
                Object mCallbackProxy = new Reflect(currentWebView).field("mCallbackProxy").out(Object.class);
                currentWebChromeClient = new Reflect(mCallbackProxy).field("mWebChromeClient").out(WebChromeClient.class);
            }
        }catch(Exception ignored){}

        return currentWebChromeClient;
    }


    public View getViewbyPath(String path){

        KLog.v(BuildConfig.GETVIEW, "**********get view by path*********");
        KLog.v(BuildConfig.GETVIEW, path);
        List<View> targetViews = new ArrayList<View>();
        int index = -1;
        //如果有数字的，后面跟的第一个View的class是子节点的
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        String[] pathNodes = path.split("/");
        int begin = 0;
        //标准的xpath路径，起始节点就是root，应该删掉
        begin = 1;
        List<List<View>> tmpViews = new ArrayList<>();
        for(int i = 1; i < pathNodes.length; i++){
            tmpViews.add(new ArrayList<View>());
        }
        //默认根节点应该都是ViewGroup，可以这么认为？
        for(int i = 0; i < ((ViewGroup) root).getChildCount(); i++){
            View tmp = ((ViewGroup) root).getChildAt(i);
            tmpViews.get(0).add(tmp);
        }
        for(int i = 0; begin < pathNodes.length; begin++,i++){
            List<View> views = tmpViews.get(i);
            if(begin == pathNodes.length - 1){
                if(pathNodes[begin].contains("^")){
                    index = Integer.parseInt(pathNodes[begin].substring(pathNodes[begin].indexOf("^") + 1));
                }
            }
            for(int j = 0; j < views.size(); j++){
                View tmp = views.get(j);
                if(pathNodes[begin].startsWith(getViewName(tmp))){
                    //如果和path一致
                    if(begin < pathNodes.length - 1){
                        if(tmp instanceof ViewGroup){
                            for(int k = 0; k < ((ViewGroup) tmp).getChildCount(); k++){
                                tmpViews.get(i + 1).add(((ViewGroup) tmp).getChildAt(k));
                            }
                        }
                    }else{
                        //最后一层了，所以如果符合就直接放到结果的列表里面
                        targetViews.add(tmp);
                    }
                }
            }
        }
        if(targetViews == null || targetViews.isEmpty())
            return null;

        //默认就返回第一个（我们可以假设只会有一个匹配上吗？）
        if(index >= 0) {
            return targetViews.get(index - 1);
        }
        return targetViews.get(0);
    }



    public String getContentByWebPath(String path){


        if(!TextUtils.isEmpty(webContent))
            return webContent;
        KLog.v(BuildConfig.GETVIEW, "try to get content by web xpath: " + path);
        List<View> views = new ArrayList<View>();
        views.add(root);
        WebView webView = null;
        while(views.size() > 0){
            View now = views.remove(0);
            if(isDerivedFrom(now.getClass(), WebView.class)){
                webView = (WebView) now;
                break;
            }
            if(now instanceof ViewGroup){
                for(int i = 0;i < ((ViewGroup) now).getChildCount();i++){
                    views.add(((ViewGroup) now).getChildAt(i));
                }
            }
        }
        if(webView !=null) {
            KLog.v(BuildConfig.GETVIEW, "====find target webview======");
            getWebContent(webView);
        }

        return webContent;
    }


    public String getContentbyPath(String path){

        List<View> targetViews = new ArrayList<View>();

        int index = -1;
        //如果有数字的，后面跟的第一个View的class是子节点的
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        String[] pathNodes = path.split("/");
        List<List<View>> tmpViews = new ArrayList<>();
        for(int i = 1; i < pathNodes.length; i++){
            tmpViews.add(new ArrayList<View>());
        }
        //默认根节点应该都是ViewGroup，可以这么认为？
        for(int i = 0; i < ((ViewGroup) root).getChildCount(); i++){
            View tmp = ((ViewGroup) root).getChildAt(i);
            tmpViews.get(0).add(tmp);
        }
        for(int i = 1; i < pathNodes.length; i++){

            List<View> views = tmpViews.get(i - 1);

            if(i == pathNodes.length - 1){
                if(pathNodes[i].contains("^")){
                    index = Integer.parseInt(pathNodes[i].substring(pathNodes[i].indexOf("^") + 1));
                }
            }

            for(int j = 0; j < views.size(); j++){
                View tmp = views.get(j);
                if(pathNodes[i].startsWith(getViewName(tmp))){
                    //如果和path一致
                    if(i < pathNodes.length - 1){
                        if(tmp instanceof ViewGroup){
                            for(int k = 0; k < ((ViewGroup) tmp).getChildCount(); k++){
                                tmpViews.get(i).add(((ViewGroup) tmp).getChildAt(k));
                            }
                        }
                    }else{
                        //最后一层了，所以如果符合就直接放到结果的列表里面
                        targetViews.add(tmp);
                    }
                }
            }
        }
        String content = "";
        //默认就返回第一个（我们可以假设只会有一个匹配上吗？）
        if(index >= 0) {
            if(targetViews.size() >= index) {
                View tmp = targetViews.get(index - 1);
                if (tmp instanceof TextView) {
                    content = ((TextView) tmp).getText().toString().trim();
                }
            }
        }else{
            for(View tmp : targetViews){
                if(tmp instanceof TextView){
                    content += ((TextView) tmp).getText().toString().trim();
                }
            }
        }
        return content;
    }


    public String getContentById(String id){

        String content = "";
        int view_id = currentActivity.getResources().getIdentifier(id, null, null);
        if(view_id > 0) {
            View view = root.findViewById(view_id);
            if (view != null && view instanceof TextView) {
                content += ((TextView) view).getText().toString().trim();
            }
        }
        KLog.v(BuildConfig.GETVIEW, "get content : " + content + " , with id: " + id);
        return content;
    }

    public View getViewById(String id){

        KLog.v(BuildConfig.GETVIEW, "======getViewById===========");
        KLog.v(BuildConfig.GETVIEW, "id is: " + id);
        int view_id = currentActivity.getResources().getIdentifier(id, null, null);
        if(view_id > 0) {
            View view = root.findViewById(view_id);
            return view;
        }
        return null;
    }


    String getViewName(View view){
        String name = view.getClass().getName();
        if(name.lastIndexOf(".") >= 0){
            name = name.substring(name.lastIndexOf(".")+1);
        }
        return name;
    }


    public static void simulateClick(View view) {
        if(view == null){
            KLog.v(BuildConfig.GETVIEW, "=====bug!!!!!!========");
            return;
        }
        int width = view.getWidth();
        int height = view.getHeight();
        float x = width/2;
        float y = height/2;

        long downTime = SystemClock.uptimeMillis();
        final MotionEvent downEvent = MotionEvent.obtain(downTime, downTime,
                MotionEvent.ACTION_DOWN, x, y, 0);
        downTime += 1000;
        final MotionEvent upEvent = MotionEvent.obtain(downTime, downTime,
                MotionEvent.ACTION_UP, x, y, 0);
        view.onTouchEvent(downEvent);
        view.onTouchEvent(upEvent);
        downEvent.recycle();
        upEvent.recycle();
    }


    public static void sendEnter(){
        KLog.v(BuildConfig.GETVIEW, "====try to send enter event=======");
        Instrumentation inst = new Instrumentation();
        KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_ENTER);
        KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_ENTER);
        inst.sendKeySync(downEvent);
        inst.sendKeySync(upEvent);
    }


    String getViewPath(ViewNode view){
        String result = "";
        while(view != null){
            result = view.getView().getClass().getSimpleName() + "/"+ result;
            view = view.getParent();
        }
        return result;
    }

    public void findViewByContent(String content){
        List<ViewNode> s = new ArrayList<ViewNode>();
        ViewNode rootNode = new ViewNode(root, null);
        s.add(rootNode);
        while(s.size() > 0) {
            ViewNode now = s.remove(0);
            if(now.getView() instanceof ViewGroup){
                for(int i = 0; i < ((ViewGroup) now.getView()).getChildCount(); i++){
                    s.add(new ViewNode(((ViewGroup) now.getView()).getChildAt(i), now));
                }
            }else{
                if(now.getView() instanceof TextView){
                    if(((TextView) now.getView()).getText().toString().trim().contains(content)){
                        String path = getViewPath(now);
                        int[] position = {0, 0};
                        now.getView().getLocationOnScreen(position);
                        int width = now.getView().getWidth();
                        int height = now.getView().getHeight();
                        UtilViewNode viewNode = new UtilViewNode(currentActivity.getClass().getName(), path, position, width, height);
                        KLog.v(BuildConfig.GETVIEW,"++++++++++++++path++++++++++++++++");
                        KLog.v(BuildConfig.GETVIEW, "viewNode: " + new Gson().toJson(viewNode));
                        KLog.v(BuildConfig.GETVIEW,"++++++++++++++path++++++++++++++++");
                    }
                }
            }
        }
    }

    public void findViewByPosition(int x, int y){
        KLog.v(BuildConfig.GETVIEW, "====try to find the view with position: x, " + x + " y, " + y);
        //KLog.v(BuildConfig.GETVIEW, root.getClass().getText());
        List<ViewNode> s = new ArrayList<ViewNode>();
        ViewNode rootNode = new ViewNode(root, null);
        s.add(rootNode);
        String result = "";
        List<UtilViewNode> viewNodes = new ArrayList<>();
        while(s.size() > 0) {
            ViewNode now = s.remove(0);
            if(now.getView() instanceof ViewGroup){
                for(int i = 0; i < ((ViewGroup) now.getView()).getChildCount(); i++){
                    s.add(new ViewNode(((ViewGroup) now.getView()).getChildAt(i), now));
                }
            }else{
                View nowView = now.getView();
                int[] position = {0, 0};
                nowView.getLocationOnScreen(position);
                int width = nowView.getWidth();
                int height = nowView.getHeight();
                if(x > position[0] && x < position[0] + width && y > position[1] && y < position[1] + height){
                    String path = getViewPath(now);
                    UtilViewNode viewNode = new UtilViewNode(currentActivity.getClass().getName(), path, position, width, height);
                    KLog.v(BuildConfig.GETVIEW,"++++++++++++++path++++++++++++++++");
                    result = new Gson().toJson(viewNode);
                    viewNodes.add(viewNode);
                    KLog.v(BuildConfig.GETVIEW, "viewNode: " + result);
                    KLog.v(BuildConfig.GETVIEW,"++++++++++++++path++++++++++++++++");
                }
            }
        }
        if(Utils.isEmpty(viewNodes))
            return;

        result = new Gson().toJson(viewNodes);
        Uri saveLogUri = Uri.parse("content://ias.deepsearch.com.ias.provider.DatasProvider/save_log");
        currentActivity.getContentResolver().query(saveLogUri, new String[]{currentActivity.getClass().getName()}, "ias_getview", null, result);

    }


    //判断一个view有没有设置OnClickListener
    public View.OnClickListener getClickListener(View view){
        try {
            Class<?> viewClass = Class.forName("android.view.View");
            Class<?> listenerClass = Class.forName("android.view.View$ListenerInfo");
            Field onClickListenerField = listenerClass.getField("mOnClickListener");
            onClickListenerField.setAccessible(true);
            Field listenerfield = viewClass.getDeclaredField("mListenerInfo");
            listenerfield.setAccessible(true);
            Object mlistenerInfo = listenerfield.get(view);
            if(mlistenerInfo == null){
                //KLog.v("liuyi", "mlistenerInfo is null");
            }else{
                Object listener = onClickListenerField.get(mlistenerInfo);
                if(listener != null)
                    return (View.OnClickListener) listener;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getFieldName(Context context, String package_name, int id){
        Log.v("liuyi", "==========get field name==========");
        Log.v("liuyi", package_name + " " + id);
        //Class c = null;
        String result = null;
        try {
            result = context.getResources().getResourceEntryName(id);
        }catch (Resources.NotFoundException e){
            KLog.a("liuyi", e.getLocalizedMessage());
        }
//        try {
//            c = Class.forName(package_name + ".R$id");
//            Field[] fields = c.getDeclaredFields();
//            for (int i = 0; i < fields.length; i++) {
//                String name = fields[i].getName();
//                Log.v("liuyi",name);
//                if(fields[i].getInt(name) == id){
//                    result = name;
//                    break;
//                }
//            }
//        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
//        } catch (IllegalAccessException e) {
//            e.printStackTrace();
//        }
        Log.v("liuyi", "id name: " + result);
        return result;
    }



    //由于有些应用中没有用到RecyclerView，如果直接用RecyclerView会报找不到类的错误，所以需要用反射的方式
    public static Class getRecyclerView(){
        Class r = null;
        try {
            r = Class.forName("android.support.v7.widget.RecyclerView");
        } catch (ClassNotFoundException e) {
            return null;
        }
        return r;
    }


    public static boolean fromRecyclerView(Class target){
        Class r = getRecyclerView();
        if(r == null)
            return false;
        return r.isAssignableFrom(target);
    }

    //判断一个view有没有设置OnClickListener
    public static boolean hasClickListener(View view){
        try {
            Class<?> viewClass = Class.forName("android.view.View");
            Class<?> listenerClass = Class.forName("android.view.View$ListenerInfo");
            Field onClickListenerField = listenerClass.getField("mOnClickListener");
            onClickListenerField.setAccessible(true);

            Field listenerfield = viewClass.getDeclaredField("mListenerInfo");
            listenerfield.setAccessible(true);

            Object mlistenerInfo = listenerfield.get(view);
            if(mlistenerInfo == null){
                //Log.v("liuyi", "mlistenerInfo is null");
            }else{
                Object listener = onClickListenerField.get(mlistenerInfo);
                if(listener != null)
                    return true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

    //AbListView和GridView都是继承AdapterView，可以设置OnItemClickListener
    public static boolean hasOnItemClickListener(View view){
        if(view instanceof AdapterView)
            return false;
        try {
            Class<?> adapterViewClass = Class.forName("android.widget.AdapterView");
            Field mOnItemClickListenerField = adapterViewClass.getDeclaredField("mOnItemClickListener");
            mOnItemClickListenerField.setAccessible(true);
            Object mOnItemClickListener = mOnItemClickListenerField.get(view);
            if(mOnItemClickListener != null)
                return true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


        return false;
    }

}
